﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using CoreEx.Common.Extensions;
using CoreEx.Common.Proxy;
using LinFu.AOP.Interfaces;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using LinFu.IoC;
using CoreEx.DynamicInvoker;
namespace CoreEx.Common.Repository.Implementation
{

    [Implements(typeof(IInterceptor), ServiceName = "ServiceContractInterceptor")]
    public class ServiceContractInterceptor : IInterceptor, IInitialize
    {
        protected object Target { get; set; }

        protected Type ContractType { get; set; }

        protected IStateTracker StateTracker { get; set; }

        public ServiceContractInterceptor(Type contractType, object target)
        {
            Target = target;
            ContractType = contractType;
        }


        public object Intercept(IInvocationInfo info)
        {
            object returnValue = Target.GetType().DynamicInvoke(Target, info.TargetMethod.Name, info.Arguments);

            if (ShouldTrackChanges(info))
            {                
                RegisterTrackingTargets(returnValue);
            }
            return returnValue;                        
        }

        protected virtual bool ShouldTrackChanges(IInvocationInfo info)
        {
            var returnType = info.ReturnType.GetGenericElementType();
            if (info.ReturnType.IsEnumerable() && !returnType.IsSystemType())
                return true;
            if (!info.ReturnType.IsEnumerable() && !returnType.IsSystemType())
                return true;
            return false;
        }


        protected void RegisterTrackingTargets(object returnValue)
        {
            if (returnValue.GetType().IsEnumerable())
            {
                var collection = ((IEnumerable)returnValue);
                foreach (var target in collection)
                {
                    StateTracker.Register(target);
                }
            }
            else
                StateTracker.Register(returnValue);
        }



        public void Initialize(IServiceContainer source)
        {
            StateTracker = source.GetService<IStateTrackerRepository>().GetStateTracker(this);
        }
    }
    


    public class RepositoryInterceptor : ServiceContractInterceptor
    {
        private readonly IList<Expression> _loadExpressions = new List<Expression>();


        public RepositoryInterceptor(Type contractType, object target) : base(contractType, target)
        {
        }


        public object Intercept(IInvocationInfo info)
        {
            if (info.TargetMethod.Name == "LoadWith")
            {
                _loadExpressions.Add((Expression) info.Arguments[0]);
                return null;
            }
            

            if (info.TargetMethod.Name == "Save")
            {
         
                Target.GetType().DynamicInvoke(Target, "Save", StateTracker.GetChanges().ToList());
                StateTracker.AcceptChanges();
                return null;
            }

            return base.Intercept(info);
        }


        



    }
}
